package controller

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"device-admin/config"
	"device-admin/config/mysql"
	"device-admin/config/redis"
	"device-admin/internal/app/grpc/protoc/robotc"
	"device-admin/internal/app/grpc/service/robot"
	"device-admin/internal/app/web/service/device"
	"device-admin/internal/dao"
	"device-admin/internal/define"
	"device-admin/internal/models"

	device_grpc "device-admin/internal/app/grpc/service/device"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/response"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"google.golang.org/protobuf/proto"
)

type Device struct{}

// ResetMerchant 重置商户
func (Device) ResetMerchant(c *gin.Context) {
	var params struct {
		RobotID string `json:"robot_id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.ResetMerchant(
		c.Request.Context(),
		c.GetString("user_id"),
		c.GetString("merchant_id"),
		c.GetString("user_merchant_path"),
		params.RobotID,
	)
	response.JSON(c, nil, err)
}

// SetMerchant 设置商户
func (Device) SetMerchant(c *gin.Context) {
	var params struct {
		RobotID    string `json:"robot_id"`
		MerchantID string `json:"merchant_id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.SetMerchantAndSync(
		c.Request.Context(),
		c.GetString("user_id"),
		c.GetString("merchant_id"),
		c.GetString("user_merchant_path"),
		params.RobotID, params.MerchantID,
	)
	response.JSON(c, nil, err)
}

// SetLocation 设置位置
func (Device) SetLocation(c *gin.Context) {
	var params struct {
		RobotID    string `json:"robot_id"`    // 设备id
		LocationID string `json:"location_id"` // 位置id
		FloorID    string `json:"floor_id"`    // 楼层id
		PositionID string `json:"position_id"` // 楼层位置id
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.SetLocationAndSync(c.Request.Context(), c.GetString("user_id"), c.GetString("user_merchant_path"), params.RobotID, params.LocationID, params.FloorID, params.PositionID)
	response.JSON(c, nil, err)
}

// 设置服务电话
func (Device) SetServicePhone(c *gin.Context) {
	var params struct {
		RobotID      string `json:"robot_id"`
		ServicePhone string `json:"service_phone"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.SetServicePhone(c.Request.Context(), c.GetString("user_merchant_path"), params.RobotID, params.ServicePhone)
	response.JSON(c, nil, err)
}

func (Device) SetImages(c *gin.Context) {
	var params struct {
		RobotID string   `json:"robot_id"`
		Images  []string `json:"images"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.SetImages(c.Request.Context(), c.GetString("user_merchant_path"), params.RobotID, params.Images)
	response.JSON(c, nil, err)
}

// DeviceTypes 设备类型
func (Device) DeviceTypes(c *gin.Context) {
	online := -1
	if onlineStr, hasOnline := c.GetQuery("online"); hasOnline {
		if onlineStr != "" {
			online, _ = strconv.Atoi(onlineStr)
		}
	}
	deviceTypes := device.DeviceTypes(online, c.GetString("merchant_id"))
	response.JSON(c, deviceTypes, nil)
}

// AddDevice 添加设备
func (Device) AddDevice(c *gin.Context) {
	var params struct {
		RobotID            string `json:"robot_id"`
		IdentificationCode string `json:"identification_code"`
		DeviceType         int    `json:"device_type"`
	}
	c.ShouldBindJSON(&params)
	err := device.AddDevice(params.RobotID, params.IdentificationCode, params.DeviceType)
	response.JSON(c, nil, err)
}

// AddDevices 批量添加设备
func (Device) AddDevices(c *gin.Context) {
	var params struct {
		RobotIDPrefix string `json:"robot_id_prefix"`
		StartIndex    int    `json:"start_index"`
		EndIndex      int    `json:"end_index"`
		IndexLen      int    `json:"index_len"`
		DeviceType    int    `json:"device_type"`
	}
	c.ShouldBindJSON(&params)
	_, err := device.AddDevices(params.RobotIDPrefix, params.StartIndex, params.EndIndex, params.IndexLen, params.DeviceType)
	response.JSON(c, nil, err)
}

// ExportDevice 导出
func (Device) ExportDevice(c *gin.Context) {
	// 设置文件名和文件类型
	c.Writer.Header().Set("Content-Disposition", "attachment;filename=devices.txt")
	c.Writer.Header().Set("Content-Type", "text/plain")

	var devices []models.Device
	mysql.NewDB().Model(&models.Device{}).Select("robot_id", "identification_code").Find(&devices)

	var data strings.Builder
	data.Grow(40000)
	// 获取设备
	for index, device := range devices {
		if index > 0 {
			data.Write([]byte("\n"))
		}
		data.Write([]byte(device.RobotID + " " + device.IdentificationCode))
	}
	// 将数据写入 ResponseWriter 中
	_, err := c.Writer.WriteString(data.String())
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	// 返回 Response
	c.Status(http.StatusOK)
}

type AllDeviceType struct {
	ID                 string   `json:"id"`
	RobotID            string   `json:"robot_id"`
	Online             int      `json:"online"`
	DeviceType         int      `json:"device_type"`
	IdentificationCode string   `json:"identification_code"`
	MerchantID         string   `json:"merchant_id"`
	LocationID         string   `json:"location_id"`
	FloorName          string   `json:"floor_name"`
	LocationName       string   `json:"location_name"`
	PositionName       string   `json:"position_name"` // 精准位置名称
	Images             []string `json:"images"`
}

// AllDevice 所有设备
func (Device) AllDevice(c *gin.Context) {
	online := -1
	if onlineStr, hasOnline := c.GetQuery("online"); hasOnline {
		if onlineStr != "" {
			online, _ = strconv.Atoi(onlineStr)
		}
	}
	var fields []string
	if c.Query("fields") != "" {
		fields = strings.Split(c.Query("fields"), ",")
	} else {
		fields = []string{"id", "robot_id", "online", "device_type", "identification_code", "merchant_id", "location_id", "images"}
	}
	subMode, _ := strconv.Atoi(c.Query("sub_mode"))
	deviceList, total, err := device.DeviceList(
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		c.Query("robot_id"),
		c.Query("device_types"),
		c.Query("merchant_ids"),
		online,
		0,
		0,
		fields,
		c.Query("province_id"), c.Query("city_id"), c.Query("district_id"), c.Query("location_id"),
		subMode, 0, 0,
	)

	list := []AllDeviceType{}
	for _, dl := range deviceList {
		list = append(list, AllDeviceType{
			ID:                 dl.ID,
			RobotID:            dl.RobotID,
			Online:             dl.Online,
			DeviceType:         dl.DeviceType,
			IdentificationCode: dl.IdentificationCode,
			MerchantID:         dl.MerchantID,
			LocationID:         dl.LocationID,
			Images:             dl.Images,
		})
	}
	// JSON响应
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
	}, err)
}

func (Device) AllDeviceAd(c *gin.Context) {
	online := -1
	if onlineStr, hasOnline := c.GetQuery("online"); hasOnline {
		if onlineStr != "" {
			online, _ = strconv.Atoi(onlineStr)
		}
	}
	var fields []string
	if c.Query("fields") != "" {
		fields = strings.Split(c.Query("fields"), ",")
	} else {
		fields = []string{"id", "robot_id", "online", "device_type", "identification_code", "merchant_id", "location_id", "floor_name", "location_name", "position_name"}
	}
	subMode, _ := strconv.Atoi(c.Query("sub_mode"))
	deviceList, total, err := device.DeviceList(
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		c.Query("robot_id"),
		c.Query("device_types"),
		c.Query("merchant_ids"),
		online,
		0,
		0,
		fields,
		c.Query("province_id"), c.Query("city_id"), c.Query("district_id"), c.Query("location_id"),
		subMode, 0, 0,
	)

	list := []AllDeviceType{}
	for _, dl := range deviceList {
		list = append(list, AllDeviceType{
			ID:                 dl.ID,
			RobotID:            dl.RobotID,
			Online:             dl.Online,
			DeviceType:         dl.DeviceType,
			IdentificationCode: dl.IdentificationCode,
			MerchantID:         dl.MerchantID,
			LocationID:         dl.LocationID,
			FloorName:          dl.FloorName,
			LocationName:       dl.LocationName,
			PositionName:       dl.PositionName,
		})
	}

	AdPricePerDay := float32(define.AdPricePerDay)
	if strings.Contains(config.Config.EnvType, "test") {
		AdPricePerDay = define.AdPricePerDayTest
	}

	// JSON响应
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
		"price": AdPricePerDay,
	}, err)
}

// DeviceList 设备列表
// robotID 机器人编码, deviceType 设备类型, limit 每页条数, page 分页
func (Device) DeviceList(c *gin.Context) {
	online := -1
	robotID := c.Query("robot_id")
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	if onlineStr, hasOnline := c.GetQuery("online"); hasOnline {
		if onlineStr != "" {
			online, _ = strconv.Atoi(onlineStr)
		}
	}
	subMode, _ := strconv.Atoi(c.Query("sub_mode"))
	list, total, err := device.DeviceList(
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		robotID,
		c.Query("device_types"),
		c.Query("merchant_ids"),
		online,
		page,
		limit,
		nil,
		c.Query("province_id"), c.Query("city_id"), c.Query("district_id"), c.Query("location_id"),
		subMode,
		0,
		0,
	)

	// JSON响应
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
	}, err)
}

// DeviceList 设备列表
// robotID 机器人编码, deviceType 设备类型, limit 每页条数, page 分页
func (Device) DeviceListAd(c *gin.Context) {

	online := -1
	robotID := c.Query("robot_id")
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	if onlineStr, hasOnline := c.GetQuery("online"); hasOnline {
		if onlineStr != "" {
			online, _ = strconv.Atoi(onlineStr)
		}
	}
	subMode, _ := strconv.Atoi(c.Query("sub_mode"))
	longitude_in, err := strconv.ParseFloat(c.Query("longitude"), 64)
	latitude_in, err := strconv.ParseFloat(c.Query("latitude"), 64)
	list, total, err := device.DeviceList(
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		robotID,
		c.Query("device_types"),
		c.Query("merchant_ids"),
		online,
		page,
		limit,
		nil,
		c.Query("province_id"), c.Query("city_id"), c.Query("district_id"), c.Query("location_id"),
		subMode,
		longitude_in,
		latitude_in,
	)
	AdPricePerDay := float32(define.AdPricePerDay)
	if strings.Contains(config.Config.EnvType, "test") {
		AdPricePerDay = define.AdPricePerDayTest
	}

	// JSON响应
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
		"price": AdPricePerDay,
	}, err)
}

// DeviceDetail 设备详情
func (Device) DeviceDetail(c *gin.Context) {
	robotID := c.Query("robot_id")
	list, total, _ := device.DeviceList(
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		robotID,
		"",
		"",
		-1,
		1,
		1,
		nil,
		"", "", "", "",
		0, 0, 0,
	)
	if total <= 0 {
		response.JSON(c, nil, errorx.New("设备不存在", -1))
		return
	}
	dateByes, _ := json.Marshal(list[0])
	var ret map[string]interface{}
	json.Unmarshal(dateByes, &ret)
	if list[0].Online == 1 {
		rtInfo := robot.GetRealtimeInfo(robotID)
		for k, v := range rtInfo {
			ret[k] = v
		}
	}
	ret["price"] = 300
	response.JSON(c, ret, nil)
}

func (Device) DeviceDetailAd(c *gin.Context) {
	robotID := c.Query("robot_id")
	list, total, _ := device.DeviceList(
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		robotID,
		"",
		"",
		-1,
		1,
		1,
		nil,
		"", "", "", "",
		0, 0, 0,
	)
	if total <= 0 {
		response.JSON(c, nil, errorx.New("设备不存在", -1))
		return
	}
	dateByes, _ := json.Marshal(list[0])
	var ret map[string]interface{}
	json.Unmarshal(dateByes, &ret)
	if list[0].Online == 1 {
		rtInfo := robot.GetRealtimeInfo(robotID)
		for k, v := range rtInfo {
			ret[k] = v
		}
	}

	AdPricePerDay := float32(define.AdPricePerDay)
	if strings.Contains(config.Config.EnvType, "test") {
		AdPricePerDay = define.AdPricePerDayTest
	}
	ret["price"] = AdPricePerDay
	response.JSON(c, ret, nil)
}

// ActiveRecords 活跃记录
func (Device) ActiveRecords(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))

	list, total, err := device.ActiveRecords(c.Query("robot_id"), page, limit)
	// 返回json数据
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
	}, err)
}

// AlarmRecords 告警记录
func (Device) AlarmRecord(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))

	list, total, err := device.AlarmRecords(c.Query("robot_id"), page, limit)
	// 返回json数据
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
	}, err)
}

// TaskRecords 任务执行记录
func (Device) TaskRecords(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))

	list, total, err := device.TaskRecords(c.Query("robot_id"), page, limit)
	// 返回json数据
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
	}, err)
}

// AVGOnlineDevice 获取商户平均在线设备
func (Device) AVGOnlineDevice(c *gin.Context) {
	startTime, _ := strconv.ParseInt(c.Query("start_time"), 10, 64)
	endTime, _ := strconv.ParseInt(c.Query("end_time"), 10, 64)
	merchantID := c.Query("merchant_id")
	if merchantID == "" {
		merchantID = c.GetString("merchant_id")
	}
	avgOnlineDevice, avgOnlinePercent, totalDevice, totalOnlineDevice, err := device.GetAvgOnlineDevice(
		c.Request.Context(),
		merchantID,
		c.Query("location_id"),
		startTime, endTime,
	)
	response.JSON(c, map[string]interface{}{
		"avg_online_device":   avgOnlineDevice,
		"avg_online_percent":  avgOnlinePercent,
		"total_device":        totalDevice,
		"total_online_device": totalOnlineDevice,
	}, err)
}

// AVGActiveDevice 获取商户平均活跃设备
func (Device) AVGActiveDevice(c *gin.Context) {
	startTime, _ := strconv.ParseInt(c.Query("start_time"), 10, 64)
	endTime, _ := strconv.ParseInt(c.Query("end_time"), 10, 64)
	merchantID := c.Query("merchant_id")
	if merchantID == "" {
		merchantID = c.GetString("merchant_id")
	}
	avgActiveDevice, avgActivePercent, totalDevice, totalActiveDevice, err := device.GetAvgActiveDevice(
		c.Request.Context(),
		merchantID,
		c.Query("location_id"),
		startTime, endTime,
	)
	response.JSON(c, map[string]interface{}{
		"avg_active_device":   avgActiveDevice,
		"avg_active_percent":  avgActivePercent,
		"total_device":        totalDevice,
		"total_active_device": totalActiveDevice,
	}, err)
}

// DeviceLog 设备操作日志
func (Device) DeviceLog(c *gin.Context) {
	// 日志分类
	// 日志类型
	var logCategory, logType int
	if logCategoryStr, hasLogCategoryStr := c.GetQuery("log_category"); !hasLogCategoryStr {
		logCategory = -1
	} else {
		logCategory, _ = strconv.Atoi(logCategoryStr)
	}
	if logTypeStr, hasLogTypeStr := c.GetQuery("log_category"); !hasLogTypeStr {
		logType = -1
	} else {
		logType, _ = strconv.Atoi(logTypeStr)
	}
	// 分页参数
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	// 查询
	list, total, err := device.DeviceLog(c.Query("robot_id"), logCategory, logType, page, limit)
	// 返回json数据
	response.JSON(c, gin.H{
		"list":  list,
		"total": total,
	}, err)
}

// SystemVersion 系统信息
func (Device) SystemVersion(c *gin.Context) {
	if c.Query("robot_id") == "" {
		response.JSON(c, nil, errorx.New("机器id不能为空"))
		return
	}
	redisCtx, redisCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
	defer redisCtxCancel()
	data, err := redis.NewDB().HGet(redisCtx, define.RedisRobotRTInfo+c.Query("robot_id"), "system_version").Result()
	// 读取缓存数据
	if err == nil {
		dataBytes := []byte(data)
		vers := []map[string]interface{}{}
		rsp := &robotc.RspGetSysVersion{}
		proto.Unmarshal(dataBytes, rsp)
		versionItems := rsp.GetSysInfo()
		for _, item := range versionItems {
			info := make(map[string]interface{})
			info["type"] = define.DeviceComponentType[int(item.GetType())]
			info["version"] = string(item.GetVersion())
			info["date"] = string(item.GetDate())
			vers = append(vers, info)
		}
		response.JSON(c, vers, nil)
		return
	}
	response.JSON(c, nil, nil)
}

// 获取环境因子的名称
func (Device) GetMetricNames(c *gin.Context) {
	res, err := device.GetDeviceMetricNames(c.Query("robot_id"))
	response.JSON(c, res, err)
}

// 获取环境因子的数值
func (Device) GetMetricData(c *gin.Context) {
	startTime, _ := strconv.Atoi(c.Query("start_time"))
	endTime, _ := strconv.Atoi(c.Query("end_time"))
	res, err := device.GetDeviceMetricData(c.Query("robot_id"), c.Query("metric_names"), int64(startTime), int64(endTime))
	response.JSON(c, res, err)
}

// GetStatusList 状态列表
func (Device) StatusList(c *gin.Context) {
	online, _ := strconv.Atoi(c.Query("online"))
	workMode, _ := strconv.Atoi(c.Query("work_mode"))
	saleStatus, _ := strconv.Atoi(c.Query("sale_status"))
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	list, total,
		totalOnline95, totalOffline95,
		totalOnline97, totalOffline97,
		totalOnline98, totalOffline98,
		err := device.DeviceStatusList(
		c.Request.Context(),
		c.GetString("merchant_id"), c.GetString("user_merchant_path"), c.Query("merchant_id"),
		c.Query("robot_id"),
		online,
		c.Query("province_id"), c.Query("city_id"), c.Query("district_id"), c.Query("location_id"),
		workMode, saleStatus,
		page,
		limit,
	)
	response.JSON(c, map[string]interface{}{
		"list":             list,
		"total":            total,
		"total_online_95":  totalOnline95,
		"total_offline_95": totalOffline95,
		"total_online_97":  totalOnline97,
		"total_offline_97": totalOffline97,
		"total_online_98":  totalOnline98,
		"total_offline_98": totalOffline98,
	}, err)
}

type Terminal struct{}

// VersionOption 版本选项
func (Terminal) VersionOption(c *gin.Context) {
	versions := device.Terminal{}.VersionOption(c.Request.Context(), c.Query("terminal_type"))
	response.JSON(c, map[string]interface{}{
		"list": versions,
	}, nil)
}

// TerminalList 终端列表
func (Terminal) TerminalList(c *gin.Context) {
	robotID := c.Query("robot_id")
	terminalType := c.Query("terminal_type")
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	// 在线状态
	online := -1
	if onlineStr, exists := c.GetQuery("online"); exists {
		online, _ = strconv.Atoi(onlineStr)
	}
	// 终端列表
	list, total, err := device.Terminal{}.List(
		c.Request.Context(),
		c.GetString("merchant_id"),
		c.GetString("merchant_path"),
		robotID, terminalType,
		online,
		c.Query("version"),                                                 // 软件版本筛选
		c.Query("province_id"), c.Query("city_id"), c.Query("district_id"), // 省市区筛选
		page, limit,
	)
	response.JSON(c, map[string]interface{}{
		"list":  list,
		"total": total,
	}, err)
}

// PackageList 升级包列表
func (Terminal) PackageList(c *gin.Context) {
	terminalType := c.Query("terminal_type")
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	list, total, err := device.UpgradePackage{}.List(terminalType, page, limit)
	response.JSON(c, map[string]interface{}{
		"list":  list,
		"total": total,
	}, err)
}

type FirmwareVersion struct{}

// 新增版本
func (FirmwareVersion) Add(c *gin.Context) {
	var params struct {
		Version      string           `json:"version"`
		TerminalType string           `json:"terminal_type"`
		ChangeLog    string           `json:"change_log"`
		Pkgs         []device.ArchPkg `json:"pkgs"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)

	id, err := device.UpgradeVersion{}.Add(c.Request.Context(), params.Version, params.TerminalType, params.ChangeLog, params.Pkgs)
	response.JSON(c, map[string]interface{}{
		"id": id,
	}, err)
}

// Update 更新版本
func (FirmwareVersion) Update(c *gin.Context) {
	var params struct {
		ID           string           `json:"id"`
		Version      string           `json:"version"`
		TerminalType string           `json:"terminal_type"`
		ChangeLog    string           `json:"change_log"`
		Pkgs         []device.ArchPkg `json:"pkgs"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradeVersion{}.Update(c.Request.Context(), params.ID, params.Version, params.TerminalType, params.ChangeLog, params.Pkgs)
	response.JSON(c, nil, err)
}

// Detail 版本详情
func (FirmwareVersion) Detail(c *gin.Context) {
	detail, err := device.UpgradeVersion{}.Detail(c.Request.Context(), c.Query("id"))
	response.JSON(c, detail, err)
}

// List 版本列表
func (FirmwareVersion) List(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	total, list, err := device.UpgradeVersion{}.List(
		c.Request.Context(),
		c.Query("version"),
		c.Query("terminal_type"),
		page,
		limit,
	)
	response.JSON(c, map[string]interface{}{
		"total": total,
		"list":  list,
	}, err)
}

// Delete 删除版本
func (FirmwareVersion) Delete(c *gin.Context) {
	var params struct {
		ID string `json:"id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradeVersion{}.Delete(c.Request.Context(), params.ID)
	response.JSON(c, nil, err)
}

// AddPackage 新增升级包
func (Terminal) AddPackage(c *gin.Context) {
	var params struct {
		Version      string `json:"version"`
		TerminalType string `json:"terminal_type"`
		FilePath     string `json:"file_path"`
		ChangeLog    string `json:"change_log"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	packageID, err := device.UpgradePackage{}.AddPackage(
		c.Request.Context(),
		params.Version,
		params.TerminalType,
		params.FilePath,
		params.ChangeLog,
	)
	response.JSON(c, map[string]interface{}{
		"id": packageID,
	}, err)
}

// UpdatePackage 更新升级包
func (Terminal) UpdatePackage(c *gin.Context) {
	var params struct {
		ID           string `json:"id"`
		Version      string `json:"version"`
		TerminalType string `json:"terminal_type"`
		FilePath     string `json:"file_path"`
		ChangeLog    string `json:"change_log"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradePackage{}.UpdatePackage(params.ID, params.Version, params.TerminalType, params.FilePath, params.ChangeLog)
	response.JSON(c, nil, err)
}

// DeletePackage 删除升级包
func (Terminal) DeletePackage(c *gin.Context) {
	var params struct {
		ID string `json:"id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradePackage{}.DeletePackage(params.ID)
	response.JSON(c, nil, err)
}

// ScheduleDetail 升级计划详情
func (Terminal) ScheduleDetail(c *gin.Context) {
	detail, err := device.UpgradeSchedule{}.Detail(c.Query("id"))
	response.JSON(c, detail, err)
}

// ScheduleList 升级计划列表
func (Terminal) ScheduleList(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	terminalType := c.Query("terminal_type")
	list, total, err := device.UpgradeSchedule{}.List(terminalType, page, limit)
	response.JSON(c, map[string]interface{}{
		"list":  list,
		"total": total,
	}, err)
}

// AddSchedule 新增升级计划
func (Terminal) AddSchedule(c *gin.Context) {
	var params struct {
		TerminalType    string `json:"terminal_type"`
		UpgradeVersion  string `json:"upgrade_version"`
		IncludeRobotIDs string `json:"include_robot_ids"`
		StartTime       int64  `json:"start_time"`
		EndTime         int64  `json:"end_time"`
		ForceUpgrade    int64  `json:"force_upgrade"`
		AutoUpgrade     int64  `json:"auto_upgrade"`
		Mode            int64  `json:"mode"`
		Name            string `json:"name"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	// 默认为自动安装
	if params.AutoUpgrade == 0 { // 1为自动安装，2为手动安装
		params.AutoUpgrade = 1
	}
	scheduleID, err := device.UpgradeSchedule{}.AddSchedule(
		c.Request.Context(),
		c.GetString("user_id"),
		params.TerminalType,
		params.UpgradeVersion,
		params.IncludeRobotIDs,
		params.StartTime,
		params.EndTime,
		params.ForceUpgrade,
		params.Mode,
		params.AutoUpgrade,
		params.Name,
	)
	response.JSON(c, map[string]interface{}{
		"id": scheduleID,
	}, err)
}

// UpdateSchedule 更新升级计划
func (Terminal) UpdateSchedule(c *gin.Context) {
	var params struct {
		ID              string `json:"id"`
		TerminalType    string `json:"terminal_type"`
		UpgradeVersion  string `json:"upgrade_version"`
		IncludeRobotIDs string `json:"include_robot_ids"`
		StartTime       int64  `json:"start_time"`
		EndTime         int64  `json:"end_time"`
		ForceUpgrade    int64  `json:"force_upgrade"`
		AutoUpgrade     int64  `json:"auto_upgrade"`
		Mode            int64  `json:"mode"`
		Name            string `json:"name"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	// 默认为自动安装
	if params.AutoUpgrade == 0 { // 1为自动安装，2为手动安装
		params.AutoUpgrade = 1
	}
	err := device.UpgradeSchedule{}.UpdateSchedule(
		c.Request.Context(),
		c.GetString("user_id"),
		params.ID,
		params.TerminalType,
		params.UpgradeVersion,
		params.IncludeRobotIDs,
		params.StartTime,
		params.EndTime,
		params.ForceUpgrade,
		params.Mode,
		params.AutoUpgrade,
		params.Name,
	)
	response.JSON(c, nil, err)
}

// DeleteSchedule 删除升级计划
func (Terminal) DeleteSchedule(c *gin.Context) {
	var params struct {
		ID string `json:"id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradeSchedule{}.DeleteSchedule(params.ID)
	response.JSON(c, nil, err)
}

// UpgradeTerminals 升级计划终端列表
func (Terminal) UpgradeTerminals(c *gin.Context) {
	scheduleID := c.Query("schedule_id")
	terminalType := c.Query("terminal_type")
	robotID := c.Query("robot_id")
	page, _ := strconv.Atoi(c.Query("page"))
	limit, _ := strconv.Atoi(c.Query("limit"))
	list, total, success, err := device.UpgradeSchedule{}.UpgradeTerminals(scheduleID, terminalType, robotID, page, limit)
	response.JSON(c, map[string]interface{}{
		"list":    list,
		"total":   total,
		"success": success,
	}, err)
}

// StartUpgrade 开始安装
func (Terminal) StartUpgrade(c *gin.Context) {
	var params struct {
		RobotID      string `json:"robot_id"`
		TerminalType string `json:"terminal_type"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradeSchedule{}.StartManualUpgrade(params.TerminalType, params.RobotID)
	response.JSON(c, nil, err)
}

// BatchInstall 批量安装
func (Terminal) BatchInstall(c *gin.Context) {
	var params struct {
		ScheduleID string `json:"schedule_id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := device.UpgradeSchedule{}.BatchInstall(c.Request.Context(), params.ScheduleID)
	response.JSON(c, nil, err)
}

type TerminalConfig struct{}

// GetConfig 获取终端配置
func (TerminalConfig) GetConfigs(c *gin.Context) {
	data, err := device.TerminalConfig{}.GetConfigs(c.Request.Context(), c.Query("robot_id"), c.Query("terminal_type"))
	response.JSON(c, map[string]interface{}{
		"list":  data,
		"total": len(data),
	}, err)
}

// SaveConfig 保存终端配置
func (TerminalConfig) SaveConfig(c *gin.Context) {
	var params struct {
		RobotID      string `json:"robot_id"`
		TerminalType string `json:"terminal_type"`
		Configs      []struct {
			Key   string `json:"key"`
			Value string `json:"value"`
		} `json:"configs"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	records := []*models.TerminalConfig{}
	for _, config := range params.Configs {
		records = append(records, &models.TerminalConfig{Key: config.Key, Value: config.Value})
	}
	successCount, err := device.TerminalConfig{}.SaveConfig(
		c.Request.Context(),
		params.RobotID,
		params.TerminalType,
		records,
		c.GetString("user_id"),
	)
	response.JSON(c, map[string]interface{}{
		"success_count": successCount,
	}, err)
}

// GetConfigLog 获取配置修改日志
func (TerminalConfig) GetConfigLogs(c *gin.Context) {
	startTime, _ := strconv.ParseInt(c.Query("start_time"), 10, 64)
	endTime, _ := strconv.ParseInt(c.Query("end_time"), 10, 64)
	page, _ := strconv.ParseInt(c.Query("page"), 10, 64)
	limit, _ := strconv.ParseInt(c.Query("limit"), 10, 64)
	data, err := device.TerminalConfig{}.GetConfigLogs(
		c.Request.Context(),
		c.Query("robot_id"),
		c.Query("terminal_type"),
		startTime,
		endTime,
		int(page),
		int(limit),
	)
	response.JSON(c, map[string]interface{}{
		"list":  data,
		"total": len(data),
	}, err)
}

type TerminalLog struct{}

// LogList 终端日志列表
func (TerminalLog) LogList(c *gin.Context) {
	time, _ := strconv.ParseInt(c.Query("time"), 10, 64)
	list, err := device_grpc.GetLogList(c.Request.Context(), c.Query("robot_id"), c.Query("terminal_type"), time)
	response.JSON(c, map[string]interface{}{
		"list":  list,
		"total": len(list),
	}, err)
}

// DownloadLog 下载终端日志
func (TerminalLog) DownloadLog(c *gin.Context) {
	content, _ := device_grpc.GetLogContent(c.Request.Context(), c.Query("robot_id"), c.Query("terminal_type"), c.Query("log_file_name"))
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", c.Query("log_file_name")))
	c.Header("Content-Type", "text/plain")
	c.Header("Content-Length", strconv.Itoa(len(content)))
	c.Writer.Write(content)
}

type DevicePosition struct{}

// List 楼层位置列表
func (DevicePosition) List(c *gin.Context) {
	list, err := dao.DevicePosition{}.List(c.Request.Context(), c.Query("floor_id"))
	response.JSON(c, map[string]interface{}{
		"list": list,
	}, err)
}

// Add 新增楼层位置
func (DevicePosition) Add(c *gin.Context) {
	var params struct {
		FloorID      string `json:"floor_id"`
		PositionName string `json:"position_name"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	id, err := dao.DevicePosition{}.Add(c.Request.Context(), params.FloorID, params.PositionName)
	response.JSON(c, map[string]interface{}{
		"id": id,
	}, err)
}

// Edit 更新楼层位置
func (DevicePosition) Update(c *gin.Context) {
	var params struct {
		ID           string `json:"id"`
		PositionName string `json:"position_name"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := dao.DevicePosition{}.Update(c.Request.Context(), params.ID, params.PositionName)
	response.JSON(c, nil, err)
}

// Delete 删除楼层位置
func (DevicePosition) Delete(c *gin.Context) {
	var params struct {
		PositionID string `json:"id"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	err := dao.DevicePosition{}.Delete(c.Request.Context(), params.PositionID)
	response.JSON(c, nil, err)
}

type UserDevice struct{}

// Set 设置用户设备
func (UserDevice) Set(c *gin.Context) {
	var params struct {
		RobotIDs string `json:"robot_ids"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	device.UserDevice{}.Set(c.Request.Context(), c.GetString("user_id"), strings.Split(params.RobotIDs, ","))
	response.JSON(c, nil, nil)
}

// Get 获取用户设备
func (UserDevice) Get(c *gin.Context) {
	robotIDs := device.UserDevice{}.Get(c.Request.Context(), c.GetString("user_id"))
	response.JSON(c, map[string]interface{}{
		"robot_ids": robotIDs,
	}, nil)
}
